home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sun Solutions 1997 April to September
/
Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso
/
products
/
bin
/
httpd
/
src
/
http_dir.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-18
|
18KB
|
702 lines
/*
* http_dir.c: Handles the on-the-fly html index generation
*
* All code contained herein is covered by the Copyright as distributed
* in the README file in the main directory of the distribution of
* NCSA HTTPD.
*
* 03-23-93 Rob McCool
* Wrote base code up to release 1.3
*
* 03-12-95 blong
* Added patch by Roy T. Fielding <fielding@avron.ICS.UCI.EDU>
* to fix missing trailing slash for parent directory
*/
/* httpd.h includes proper directory file */
#include "httpd.h"
struct ent {
char *name;
char *icon;
char *alt;
char *desc;
size_t size;
time_t lm;
struct ent *next;
};
struct item {
int type;
char *apply_to;
char *apply_path;
char *data;
struct item *next;
};
static struct item *icon_list, *alt_list, *desc_list, *ign_list;
static struct item *hdr_list, *rdme_list, *opts_list;
static int dir_opts;
void init_indexing() {
icon_list = NULL;
alt_list = NULL;
desc_list = NULL;
ign_list = NULL;
hdr_list = NULL;
rdme_list = NULL;
opts_list = NULL;
}
void kill_item_list(struct item *p) {
struct item *q;
while(p) {
if(p->apply_to) free(p->apply_to);
if(p->apply_path) free(p->apply_path);
if(p->data) free(p->data);
q = p;
p = p->next;
free(q);
}
}
void kill_indexing() {
kill_item_list(icon_list);
kill_item_list(alt_list);
kill_item_list(desc_list);
kill_item_list(ign_list);
kill_item_list(hdr_list);
kill_item_list(rdme_list);
kill_item_list(opts_list);
}
struct item *new_item(int type, char *to, char *path, char *data, FILE *out)
{
struct item *p;
if(!(p = (struct item *)malloc(sizeof(struct item))))
die(NO_MEMORY,"new_item",out);
p->type = type;
if(data) {
if(!(p->data = strdup(data)))
die(NO_MEMORY,"new_item",out);
} else
p->data = NULL;
if(to) {
if(!(p->apply_to = (char *)malloc(strlen(to) + 2)))
die(NO_MEMORY,"new_item",out);
if((type == BY_PATH) && (!is_matchexp(to))) {
p->apply_to[0] = '*';
strcpy(&p->apply_to[1],to);
} else
strcpy(p->apply_to,to);
} else
p->apply_to = NULL;
if(!(p->apply_path = (char *)malloc(strlen(path) + 2)))
die(NO_MEMORY,"new_item",out);
sprintf(p->apply_path,"%s*",path);
return p;
}
void add_alt(int type, char *alt, char *to, char *path, FILE *out) {
struct item *p;
if(type == BY_PATH) {
if(!strcmp(to,"**DIRECTORY**"))
strcpy(to,"^^DIRECTORY^^");
}
p = new_item(type,to,path,alt,out);
p->next = alt_list;
alt_list = p;
}
void add_icon(int type, char *icon, char *to, char *path, FILE *out) {
struct item *p;
char iconbak[MAX_STRING_LEN];
strcpy(iconbak,icon);
if(icon[0] == '(') {
char alt[MAX_STRING_LEN];
getword(alt,iconbak,',');
add_alt(type,&alt[1],to,path,out);
iconbak[strlen(iconbak) - 1] = '\0';
}
if(type == BY_PATH) {
if(!strcmp(to,"**DIRECTORY**"))
strcpy(to,"^^DIRECTORY^^");
}
p = new_item(type,to,path,iconbak,out);
p->next = icon_list;
icon_list = p;
}
void add_desc(int type, char *desc, char *to, char *path, FILE *out) {
struct item *p;
p = new_item(type,to,path,desc,out);
p->next = desc_list;
desc_list = p;
}
void add_ignore(char *ext, char *path, FILE *out) {
struct item *p;
p = new_item(0,ext,path,NULL,out);
p->next = ign_list;
ign_list = p;
}
void add_header(char *name, char *path, FILE *out) {
struct item *p;
p = new_item(0,NULL,path,name,out);
p->next = hdr_list;
hdr_list = p;
}
void add_readme(char *name, char *path, FILE *out) {
struct item *p;
p = new_item(0,NULL,path,name,out);
p->next = rdme_list;
rdme_list = p;
}
void add_opts_int(int opts, char *path, FILE *out) {
struct item *p;
p = new_item(0,NULL,path,NULL,out);
p->type = opts;
p->next = opts_list;
opts_list = p;
}
void add_opts(char *optstr, char *path, FILE *out) {
char w[MAX_STRING_LEN];
int opts = 0;
while(optstr[0]) {
cfg_getword(w,optstr);
if(!strcasecmp(w,"FancyIndexing"))
opts |= FANCY_INDEXING;
else if(!strcasecmp(w,"IconsAreLinks"))
opts |= ICONS_ARE_LINKS;
else if(!strcasecmp(w,"ScanHTMLTitles"))
opts |= SCAN_HTML_TITLES;
else if(!strcasecmp(w,"SuppressLastModified"))
opts |= SUPPRESS_LAST_MOD;
else if(!strcasecmp(w,"SuppressSize"))
opts |= SUPPRESS_SIZE;
else if(!strcasecmp(w,"SuppressDescription"))
opts |= SUPPRESS_DESC;
else if(!strcasecmp(w,"None"))
opts = 0;
}
add_opts_int(opts,path,out);
}
char *find_item(struct item *list, char *path, int path_only) {
struct item *p = list;
while(p) {
/* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
if(!(p->apply_to))
return p->data;
else if(p->type == BY_PATH) {
if(!strcmp_match(path,p->apply_to))
return p->data;
} else if(!path_only) {
char pathbak[MAX_STRING_LEN];
strcpy(pathbak,path);
content_encoding[0] = '\0';
set_content_type(pathbak);
if(!content_encoding[0]) {
if(p->type == BY_TYPE) {
if(!strcmp_match(content_type,p->apply_to))
return p->data;
}
} else {
if(p->type == BY_ENCODING) {
if(!strcmp_match(content_encoding,p->apply_to))
return p->data;
}
}
}
}
p = p->next;
}
return NULL;
}
#define find_icon(p,t) find_item(icon_list,p,t)
#define find_alt(p,t) find_item(alt_list,p,t)
#define find_desc(p) find_item(desc_list,p,0)
#define find_header(p) find_item(hdr_list,p,0)
#define find_readme(p) find_item(rdme_list,p,0)
int ignore_entry(char *path) {
struct item *p = ign_list;
while(p) {
if(!strcmp_match(path,p->apply_path))
if(!strcmp_match(path,p->apply_to))
return 1;
p = p->next;
}
return 0;
}
int find_opts(char *path) {
struct item *p = opts_list;
while(p) {
if(!strcmp_match(path,p->apply_path))
return p->type;
p = p->next;
}
return 0;
}
int insert_readme(char *name, char *readme_fname, int rule, FILE *fd) {
char fn[MAX_STRING_LEN];
FILE *r;
struct stat finfo;
int plaintext=0;
make_full_path(name,readme_fname,fn);
strcat(fn,".html");
if(stat(fn,&finfo) == -1) {
fn[strlen(fn)-5] = '\0';
if(stat(fn,&finfo) == -1)
return 0;
plaintext=1;
if(rule) bytes_sent += fprintf(fd,"<HR>%c",LF);
bytes_sent += fprintf(fd,"<PRE>%c",LF);
}
else if(rule) bytes_sent += fprintf(fd,"<HR>%c",LF);
if(!(r = fopen(fn,"r")))
return 0;
send_fd(r,fd,NULL);
fclose(r);
if(plaintext)
bytes_sent += fprintf(fd,"</PRE>%c",LF);
return 1;
}
char *find_title(char *filename) {
char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
char filebak[MAX_STRING_LEN];
FILE *thefile;
int x,y,n,p;
content_encoding[0] = '\0';
strcpy(filebak,filename);
set_content_type(filebak);
if(((!strcmp(content_type,"text/html")) ||
(strcmp(content_type,INCLUDES_MAGIC_TYPE)==0))
&& (!content_encoding[0]))
{
if(!(thefile = fopen(filename,"r")))
return NULL;
n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
titlebuf[n] = '\0';
for(x=0,p=0;titlebuf[x];x++) {
if(toupper(titlebuf[x]) == find[p]) {
if(!find[++p]) {
if((p = ind(&titlebuf[++x],'<')) != -1)
titlebuf[x+p] = '\0';
/* Scan for line breaks for Tanmoy's secretary */
for(y=x;titlebuf[y];y++)
if((titlebuf[y] == CR) || (titlebuf[y] == LF))
titlebuf[y] = ' ';
fclose(thefile);
return strdup(&titlebuf[x]);
}
} else p=0;
}
fclose(thefile);
return NULL;
}
content_encoding[0] = '\0';
return NULL;
}
void escape_html(char *fn) {
register int x,y;
char copy[MAX_STRING_LEN];
strcpy(copy,fn);
for(x=0,y=0;copy[y];x++,y++) {
if(copy[y] == '<') {
strcpy(&fn[x],"<");
x+=3;
}
else if(copy[y] == '>') {
strcpy(&fn[x],">");
x+=3;
}
else if(copy[y] == '&') {
strcpy(&fn[x],"&");
x+=4;
}
else
fn[x] = copy[y];
}
fn[x] = '\0';
}
struct ent *make_dir_entry(char *path, char *name, FILE *out) {
struct ent *p;
struct stat finfo;
char t[MAX_STRING_LEN];
char *tmp;
if((name[0] == '.') && (!name[1]))
return(NULL);
make_full_path(path,name,t);
if(ignore_entry(t))
return(NULL);
if(!(p=(struct ent *)malloc(sizeof(struct ent))))
die(NO_MEMORY,"make_dir_entry",out);
if(!(p->name=(char *)malloc(strlen(name) + 2)))
die(NO_MEMORY,"make_dir_entry",out);
if(dir_opts & FANCY_INDEXING) {
if((!(dir_opts & FANCY_INDEXING)) || stat(t,&finfo) == -1) {
strcpy(p->name,name);
p->size = -1;
p->icon = NULL;
p->alt = NULL;
p->desc = NULL;
p->lm = -1;
}
else {
p->lm = finfo.st_mtime;
p->size = -1;
p->icon = NULL;
p->alt = NULL;
p->desc = NULL;
if(S_ISDIR(finfo.st_mode)) {
if(!(p->icon = find_icon(t,1)))
if (p->icon != NULL) free(p->icon);
p->icon = find_icon("^^DIRECTORY^^",1);
if(!(tmp = find_alt(t,1))){
p->alt = (char *) malloc(sizeof(char)*4);
strcpy(p->alt,"DIR");
} else {
p->alt = strdup(tmp);
}
p->size = -1;
strncpy_dir(p->name,name,MAX_STRING_LEN);
}
else {
p->icon = find_icon(t,0);
tmp = find_alt(t,0);
if (tmp != NULL) p->alt = strdup(tmp);
p->size = finfo.st_size;
strcpy(p->name,name);
}
}
if(p->desc = find_desc(t))
p->desc = strdup(p->desc);
if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
p->desc = find_title(t);
}
else {
p->icon = NULL;
p->alt = NULL;
p->desc = NULL;
p->size = -1;
p->lm = -1;
strcpy(p->name,name);
}
return(p);
}
void send_size(size_t size, FILE *fd) {
if(size == -1) {
fputs(" -",fd);
bytes_sent += 5;
}
else {
if(!size) {
fputs(" 0K",fd);
bytes_sent += 5;
}
else if(size < 1024) {
fputs(" 1K",fd);
bytes_sent += 5;
}
else if(size < 1048576)
bytes_sent += fprintf(fd,"%4dK",size / 1024);
else
bytes_sent += fprintf(fd,"%4dM",size / 1048576);
}
}
void terminate_description(char *desc) {
int maxsize = 23;
register int x;
if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
for(x=0;desc[x] && maxsize;x++) {
if(desc[x] == '<') {
while(desc[x] != '>') {
if(!desc[x]) {
maxsize = 0;
break;
}
++x;
}
}
else --maxsize;
}
if(!maxsize) {
desc[x] = '>';
desc[x+1] = '\0';
}
}
void output_directories(struct ent **ar,int n,char *name,FILE *fd)
{
int x;
char anchor[2 * MAX_STRING_LEN + 64],t[MAX_STRING_LEN],t2[MAX_STRING_LEN];
char *tp;
if(name[0] == '\0') {
name[0] = '/'; name[1] = '\0';
}
/* aaaaargh Solaris sucks. */
fflush(fd);
if(dir_opts & FANCY_INDEXING) {
fputs("<PRE>",fd);
bytes_sent += 5;
if(tp = find_icon("^^BLANKICON^^",1))
bytes_sent += (fprintf(fd,"<IMG SRC=\"%s\" ALT=\" \"> ",tp));
bytes_sent += fprintf(fd,"Name ");
if(!(dir_opts & SUPPRESS_LAST_MOD))
bytes_sent += fprintf(fd,"Last modified ");
if(!(dir_opts & SUPPRESS_SIZE))
bytes_sent += fprintf(fd,"Size ");
if(!(dir_opts & SUPPRESS_DESC))
bytes_sent += fprintf(fd,"Description");
bytes_sent += fprintf(fd,"%c<HR>%c",LF,LF);
}
else {
fputs("<UL>",fd);
bytes_sent += 4;
}
for(x=0;x<n;x++) {
if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
/* Fixes trailing slash for fancy indexing. Thanks Roy ? */
make_full_path(name,"../",t);
getparents(t);
if(t[0] == '\0') {
t[0] = '/'; t[1] = '\0';
}
escape_uri(t);
sprintf(anchor,"<A HREF=\"%s\">",t);
strcpy(t2,"Parent Directory</A>");
}
else {
lim_strcpy(t,ar[x]->name, MAX_STRING_LEN);
strcpy(t2,t);
if(strlen(t2) > 21) {
t2[21] = '>';
t2[22] = '\0';
}
/* screws up formatting, but some need it. should fix. */
/* escape_html(t2); */
strcat(t2,"</A>");
escape_uri(t);
sprintf(anchor,"<A NAME=\"%s\" HREF=\"%s\">",t,t);
}
escape_url(t);
if(dir_opts & FANCY_INDEXING) {
if(dir_opts & ICONS_ARE_LINKS)
bytes_sent += fprintf(fd,"%s",anchor);
if((ar[x]->icon) || default_icon[0] || local_default_icon[0]) {
bytes_sent += fprintf(fd,"<IMG SRC=\"%s\" ALT=\"[%s]\">",
ar[x]->icon ? ar[x]->icon :
local_default_icon[0] ?
local_default_icon : default_icon,
ar[x]->alt ? ar[x]->alt : " ");
}
if(dir_opts & ICONS_ARE_LINKS) {
fputs("</A>",fd);
bytes_sent += 4;
}
bytes_sent += fprintf(fd," %s",anchor);
bytes_sent += fprintf(fd,"%-27.27s",t2);
if(!(dir_opts & SUPPRESS_LAST_MOD)) {
if(ar[x]->lm != -1) {
struct tm *ts = localtime(&ar[x]->lm);
strftime(t,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts);
fputs(t,fd);
bytes_sent += strlen(t);
}
else {
fputs(" ",fd);
bytes_sent += 17;
}
}
if(!(dir_opts & SUPPRESS_SIZE)) {
send_size(ar[x]->size,fd);
fputs(" ",fd);
bytes_sent += 2;
}
if(!(dir_opts & SUPPRESS_DESC)) {
if(ar[x]->desc) {
terminate_description(ar[x]->desc);
bytes_sent += fprintf(fd,"%s",ar[x]->desc);
}
}
}
else
bytes_sent += fprintf(fd,"<LI> %s %s",anchor,t2);
fputc(LF,fd);
++bytes_sent;
}
if(dir_opts & FANCY_INDEXING) {
fputs("</PRE>",fd);
bytes_sent += 6;
}
else {
fputs("</UL>",fd);
bytes_sent += 5;
}
}
int dsortf(struct ent **s1,struct ent **s2)
{
return(strcmp((*s1)->name,(*s2)->name));
}
void index_directory(char *name, FILE *fd)
{
DIR *d;
struct DIR_TYPE *dstruct;
int num_ent=0,x;
struct ent *head,*p,*q;
struct ent **ar;
char unmunged_name[HUGE_STRING_LEN];
char *tmp;
strncpy_dir(unmunged_name,name,HUGE_STRING_LEN);
unmunge_name(unmunged_name);
if(!(d=opendir(name)))
die(FORBIDDEN,unmunged_name,fd);
strcpy(content_type,"text/html");
if(!assbackwards)
send_http_header(fd);
if(header_only) {
closedir(d);
return;
}
bytes_sent = 0;
dir_opts = find_opts(name);
/* Spew HTML preamble */
bytes_sent += fprintf(fd,"<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>",
unmunged_name);
fputc(LF,fd);
++bytes_sent;
if((!(tmp = find_header(name))) || (!(insert_readme(name,tmp,0,fd))))
bytes_sent += fprintf(fd,"<H1>Index of %s</H1>%c",unmunged_name,LF);
/*
* Since we don't know how many dir. entries there are, put them into a
* linked list and then arrayificate them so qsort can use them.
*/
head=NULL;
while(dstruct=readdir(d)) {
if(p = make_dir_entry(name,dstruct->d_name,fd)) {
p->next = head;
head = p;
num_ent++;
}
}
if(!(ar=(struct ent **) malloc(num_ent*sizeof(struct ent *)))) {
closedir(d);
die(NO_MEMORY,"index_directory",fd);
}
p=head;
x=0;
while(p) {
ar[x++]=p;
p = p->next;
}
qsort((void *)ar,num_ent,sizeof(struct ent *),
#ifdef ULTRIX_BRAIN_DEATH
(int (*))dsortf);
#else
(int (*)(const void *,const void *))dsortf);
#endif
output_directories(ar,num_ent,unmunged_name,fd);
free(ar);
q = head;
while(q) {
p=q->next;
free(q->name);
if(q->desc)
free(q->desc);
if(q->alt)
free(q->alt);
free(q);
q=p;
}
closedir(d);
if(dir_opts & FANCY_INDEXING)
if(tmp = find_readme(name))
insert_readme(name,tmp,1,fd);
else {
fputs("</UL>",fd);
bytes_sent += 5;
}
fputs("</BODY>",fd);
fflush(fd);
bytes_sent += 7;
fflush(fd);
log_transaction();
}